#pragma once
#include <BWAPI.h>
#include <BWTA.h>
#include <vector>
#include <deque>
#include <map>

enum EFormations
{
        ZFNone = 0,
        ZFVLine,
        ZFHLine,
        ZFBackslash,
        ZFForeslash,
        ZFDoubleVLine,
        ZFDoubleVLineDense,
        ZFDoubleHLine,
        ZFDoubleHLineDense,
        ZFCross,
        ZFPlus,
		ZFBox,
        ZFBlock,
        ZFCircle,
        ZFDiamond,
};

class CFormation
{
public:
        typedef std::map<BWAPI::Unit*, CFormation*> TFormationPairs;
        typedef std::map<BWAPI::Unit*, int> TUnitMap;
private:
        static std::vector<CFormation*> formations;
        static TFormationPairs formationPairs;
        TUnitMap units;
		std::deque<BWAPI::Position> waypoints;
        EFormations formation;
        BWAPI::Unit *target;

        int slotSize;

        CFormation(BWAPI::Position center, EFormations formation);

        void calcSlotSize();
public:
        ~CFormation();

        void joinFormation(BWAPI::Unit* unit);
        void leaveFormation(BWAPI::Unit* unit);

		bool isWellFormed();
        bool isInPosition(BWAPI::Unit* unit);

		BWAPI::Position getPosition(int slot);
        BWAPI::Position getPosition(BWAPI::Unit* unit);

        void recalculateSlots();

        int getUnitSlot(BWAPI::Unit* unit);
        TUnitMap getUnits();

        void setFormation(EFormations formation);
        BWAPI::Position getCenter();
        void setCenter(BWAPI::Position center);
        void addWayPoint(BWAPI::Position center);
        BWAPI::Unit* getTarget();
        void setTarget(BWAPI::Unit* target);

        void disbandFormation();
        void splitFormation();

        static std::vector<CFormation*> getFormations();
        static CFormation* getFormation(BWAPI::Unit* unit);

        static CFormation* getEmptyFormation(BWAPI::Position center = BWAPI::Positions::None, EFormations formation = ZFBox);
};

void CalculateNearestSlots(CFormation::TUnitMap& units, std::map<int, BWAPI::Position> slots);
